package math.geom3d;

import math.base.CCS3d;
import math.base.Dir3d;
import math.base.Point3d;
import math.base.Vector3d;
import math.geomUtils.SurfaceType;

/**
 * @author Saga
 *
 */
public final class Plane3d extends ElementarySurface3d {
    public Plane3d() {
        this.pos = new CCS3d();
    }

    public Plane3d(final CCS3d _pos) {
        this.pos = _pos;
    }


    public Plane3d(final Point3d _origin, final Dir3d _dir) {
        final double devX = Math.abs(_dir.getX());
        final double devY = Math.abs(_dir.getY());
        final double devZ = Math.abs(_dir.getZ());

        if (devX <= devY && devX <= devY) {
            if (devY <= devZ) {
                this.pos = new CCS3d(_origin, _dir, new Dir3d(0.0, _dir.getZ(), -_dir.getY()));
            } else {
                this.pos = new CCS3d(_origin, _dir, new Dir3d(0.0, -_dir.getZ(), _dir.getY()));
            }
        } else if (devY <= devZ) {
            if (devX < devZ) {
                this.pos = new CCS3d(_origin, _dir, new Dir3d(_dir.getZ(), 0.0, -_dir.getX()));
            } else {
                this.pos = new CCS3d(_origin, _dir, new Dir3d(-_dir.getZ(), 0.0, _dir.getX()));
            }
        } else {
            if (devX < devY) {
                this.pos = new CCS3d(_origin, _dir, new Dir3d(_dir.getY(), -_dir.getX(), 0.0));
            } else {
                this.pos = new CCS3d(_origin, _dir, new Dir3d(-_dir.getY(), _dir.getX(), 0.0));
            }
        }
    }

    @Override
    public final SurfaceType getSurfaceType() {
        return SurfaceType.PLANE;
    }

    @Override
    public final void uReverse() {
        this.pos.xReverse();
    }

    @Override
    public final Surface3d uReversed() {
        return new Plane3d(this.pos.xReversed());
    }

    @Override
    public final void vReverse() {
        this.pos.yReverse();
    }

    @Override
    public final Surface3d vReversed() {
        return new Plane3d(this.pos.yReversed());
    }


    @Override
    public final boolean isUPeriodic() {
        return false;
    }

    @Override
    public final double getUPeriod() {
        throw new ArithmeticException("");
    }

    @Override
    public final boolean isVPeriodic() {
        return false;
    }

    @Override
    public final double getVPeriod() {
        throw new ArithmeticException("");
    }

    @Override
    public final double getUFirstParameter() {
        return Double.NEGATIVE_INFINITY;
    }

    @Override
    public final double getULastParameter() {
        return Double.POSITIVE_INFINITY;
    }

    @Override
    public final double getVFirstParameter() {
        return Double.NEGATIVE_INFINITY;
    }

    @Override
    public final double getVLastParameter() {
        return Double.POSITIVE_INFINITY;
    }

    @Override
    public final Point3d calcValue(final double _uParam, final double _vParam) {
        return this.pos.getOrigin().added(this.pos.getDirectX().multiplied(_uParam)
                .added(this.pos.getDirectY().multiplied(_vParam)));
    }

    @Override
    public final Vector3d calcDerivativeU(final double _uParam, final double _vParam) {
        return new Vector3d(this.pos.getDirectX());
    }

    @Override
    public final Vector3d calcDerivativeV(final double _uParam, final double _vParam) {
        return new Vector3d(this.pos.getDirectY());
    }

    @Override
    public final void calcDerivative(final double _uParam, final double _vParam,
            final Vector3d _derU,
            final Vector3d _derV) {
        _derU.setCoord(this.pos.getDirectX().getCoord());
        _derU.setCoord(this.pos.getDirectY().getCoord());
    }

    @Override
    public final Vector3d calcDerivativeN(final double _uParam, final double _vParam,
            final int _uOrder,
            final int _vOrder) {
        return null;
    }

    @Override
    public final void calcValueAndDerivative1(final double _uParam, final double _vParam,
            final Point3d _pt, final Vector3d _derU, final Vector3d _derV) {
        _pt.setCoord(this.pos.getOrigin().getCoord()
                .added(this.pos.getDirectX().getCoord().multiplied(_uParam)
                        .added(this.pos.getDirectY().getCoord().multiplied(_vParam))));

        _derU.setCoord(this.pos.getDirectX().getCoord());
        _derU.setCoord(this.pos.getDirectY().getCoord());
    }

    @Override
    public final void calcValueAndDerivative2(final double _uParam, final double _vParam,
            final Point3d _pt, final Vector3d _der1U, final Vector3d _der1V, final Vector3d _der2U,
            final Vector3d _der2V, final Vector3d _der2UV) {
        _pt.setCoord(this.pos.getOrigin().getCoord()
                .added(this.pos.getDirectX().getCoord().multiplied(_uParam)
                        .added(this.pos.getDirectY().getCoord().multiplied(_vParam))));

        _der1U.setCoord(this.pos.getDirectX().getCoord());
        _der1V.setCoord(this.pos.getDirectY().getCoord());

        _der2U.init(0.0, 0.0, 0.0);
        _der2V.init(0.0, 0.0, 0.0);
        _der2UV.init(0.0, 0.0, 0.0);
    }

    @Override
    public final void calcValueAndDerivative3(final double _uParam, final double _vParam,
            final Point3d _pt, final Vector3d _der1U, final Vector3d _der1V, final Vector3d _der2U,
            final Vector3d _der2V, final Vector3d _der2UV, final Vector3d _der3U,
            final Vector3d _der3V, final Vector3d _der3UUV, final Vector3d _der3UVV) {
        _pt.setCoord(this.pos.getOrigin().getCoord()
                .added(this.pos.getDirectX().getCoord().multiplied(_uParam)
                        .added(this.pos.getDirectY().getCoord().multiplied(_vParam))));

        _der1U.setCoord(this.pos.getDirectX().getCoord());
        _der1V.setCoord(this.pos.getDirectY().getCoord());

        _der2U.init(0.0, 0.0, 0.0);
        _der2V.init(0.0, 0.0, 0.0);
        _der2UV.init(0.0, 0.0, 0.0);

        _der3U.init(0.0, 0.0, 0.0);
        _der3V.init(0.0, 0.0, 0.0);
        _der3UUV.init(0.0, 0.0, 0.0);
        _der3UVV.init(0.0, 0.0, 0.0);
    }

    @Override
    public final Curve3d calcUISOCurve(final double _param) {
        return new Line3d(this.pos.getOrigin().added(this.pos.getDirectX().multiplied(_param)),
                this.pos.getDirectY());
    }

    @Override
    public final Curve3d calcVISOCurve(final double _param) {
        return new Line3d(this.pos.getOrigin().added(this.pos.getDirectY().multiplied(_param)),
                this.pos.getDirectX());
    }

    @Override
    public final Plane3d clone() {
        return null;
    }
}
